#!/bin/bash

# 设置文件备份函数
mk_bak() {
    local file_path="${@: -1}"
    if [ -e "${file_path}" ]
    then
        cp -av "${file_path}" "${file_path}.$(date +%F_%s)"
    else
        echo "not exist file ${file_path}"
    fi
}


#################################################################################
# 确保禁用IP转发
# 确保禁用了数据包重定向发送
# 确保不接受源路由数据包
# 确保启用了反向路径过滤
# 确保不接受ICMP重定向
# 确保不接受secure ICMP重定向
# 确保不接受IPv6路由器通告
# 确保不接受IPv6重定向
#################################################################################
sysctl_path='/etc/sysctl.conf'
typeset -A sysctl_cfg_kv=(
    ['net.ipv6.conf.all.accept_redirects']='0'
    ['net.ipv6.conf.default.accept_redirects']='0'
    ['net.ipv6.conf.all.accept_ra']='0'
    ['net.ipv6.conf.default.accept_ra']='0'
#    ['net.ipv4.tcp_syncookies']='1'
    ['net.ipv4.conf.all.rp_filter']='1'
    ['net.ipv4.conf.default.rp_filter']='1'
#    ['net.ipv4.conf.all.log_martians']='1'
#    ['net.ipv4.conf.default.log_martians']='1'
    ['net.ipv4.conf.all.secure_redirects']='0'
    ['net.ipv4.conf.default.secure_redirects']='0'
    ['net.ipv4.conf.all.accept_redirects']='0'
    ['net.ipv4.conf.default.accept_redirects']='0'
    ['net.ipv4.conf.all.accept_source_route']='0'
    ['net.ipv4.conf.default.accept_source_route']='0'
    ['net.ipv4.conf.all.send_redirects']='0'
    ['net.ipv4.conf.default.send_redirects']='0'
    ['net.ipv4.ip_forward']='0'
)

mk_bak ${sysctl_path} &&
for key in "${!sysctl_cfg_kv[@]}"
do
    value=${sysctl_cfg_kv[$key]}
    if grep -iP "^\s*${key}" ${sysctl_path}
    then
        # 注意：此处Ic表示忽略大小写匹配后替换原配置行
        sed -i -r "/^[ \t]*${key}[ =]*[01]/Ic${key} = ${value}" ${sysctl_path}
    else
        sed -i -r "\$a${key} = ${value}" ${sysctl_path}
    fi
    sysctl -w "${key}=${value}"
done

sysctl -w net.ipv6.route.flush=1
sysctl -w net.ipv4.route.flush=1

#############################################################
# 确保已配置SSH警告标语
# 确保SSH MaxAuthTries设置为4或更低
# 确保SSH LogLevel设置为INFO
# 确保已配置SSH空闲超时间隔
#############################################################
ssh_path='/etc/ssh/sshd_config'
typeset -A sshd_cfg_kv=(
#    ['HostbasedAuthentication']='no'
#    ['IgnoreRhosts']='yes'
#    ['X11Forwarding']='no'
      ['LogLevel']='INFO'
#    ['Protocol']='2'
      ['Banner']='/etc/issue.net'
#    ['LoginGraceTime']='60'
#    ['MACs']='hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com'
      ['MaxAuthTries']='4'
      ['ClientAliveInterval']='300'
      ['ClientAliveCountMax']='0'
)

mk_bak ${ssh_path} &&
for key in "${!sshd_cfg_kv[@]}"
do
    value=${sshd_cfg_kv[$key]}
    if grep -iP "^\s*${key}" ${ssh_path}
    then
        # 注意：此处Ic表示忽略大小写匹配后替换原配置行
        sed -i -r "/^[ \t]*${key}/Ic${key} ${value}" ${ssh_path}
    else
        sed -i -r "\$a${key} ${value}" ${ssh_path}
    fi
done

mk_bak "/etc/issue.net" &&
echo "" > "/etc/issue.net"
sshd -t &&
systemctl restart sshd

####################################################################
# 确保已禁用IPv6
####################################################################
grub_path='/etc/default/grub'
grub_cfg_path='/boot/grub2/grub.cfg'

mk_bak ${grub_path} &&
mk_bak ${grub_cfg_path} &&
cat <<EOF > ${grub_path} &&
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="quiet elevator=noop console=ttyS0,115200 console=tty0 vconsole.keymap=us crashkernel=1800M-64G:256M,64G-128G:512M,128G-:768M vconsole.font=latarcyrheb-sun16 i8042.noaux net.ifnames=0 biosdevname=0 intel_idle.max_cstate=1 intel_pstate=disable iommu=pt amd_iommu=on audit=1 ipv6.disable=1"
GRUB_DISABLE_RECOVERY="true"
#GRUB_DISABLE_LINUX_UUID="true"
EOF
grub2-mkconfig > /boot/grub2/grub.cfg

######################################################################
# 确保配置了密码尝试失败的锁定
######################################################################
systemauth_path='/etc/pam.d/system-auth'
passwordauth_path='/etc/pam.d/password-auth'

mk_bak ${systemauth_path} &&
mk_bak ${passwordauth_path} &&
cat <<EOF > ${systemauth_path} &&
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth        required      pam_env.so
auth        required      pam_tally2.so deny=5 onerr=fail unlock_time=900
auth        required      pam_tally2.so deny=5 onerr=fail unlock_time=900
auth        required      pam_faillock.so preauth audit silent deny=5 unlock_time=900
auth        [success=1 default=bad] pam_unix.so
auth        [default=die] pam_faillock.so authfail audit deny=5 unlock_time=900
auth        sufficient    pam_faillock.so authsucc audit deny=5 unlock_time=900
auth        required      pam_faildelay.so delay=2000000
auth        sufficient    pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid >= 1000 quiet_success
auth        required      pam_deny.so
account     required      pam_tally2.so
account     required      pam_unix.so
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid < 1000 quiet
account     required      pam_permit.so
account     required      pam_tally2.so

password    requisite     pam_pwquality.so minlen=9 try_first_pass local_users_only retry=3 authtok_type=enforce_for_root ocredit=0 lcredit=-1 ucredit=-1 dcredit=-1 [badwords=first2012++]
password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass remember=5 use_authtok


password    required      pam_deny.so

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
-session     optional      pam_systemd.so
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_unix.so

EOF

cat <<EOF > ${passwordauth_path} 
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth        required      pam_env.so
auth        required      pam_tally2.so deny=5 onerr=fail unlock_time=900
auth        required      pam_faillock.so preauth audit silent deny=5 unlock_time=900
auth        [success=1 default=bad] pam_unix.so
auth        [default=die] pam_faillock.so authfail audit deny=5 unlock_time=900
auth        sufficient    pam_faillock.so authsucc audit deny=5 unlock_time=900
auth        required      pam_faildelay.so delay=2000000
auth        sufficient    pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid >= 1000 quiet_success
auth        required      pam_deny.so

account     required      pam_tally2.so
account     required      pam_unix.so
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid < 1000 quiet
account     required      pam_permit.so

password    requisite     pam_pwquality.so minlen=9 try_first_pass local_users_only retry=3 authtok_type=enforce_for_root ocredit=0 lcredit=-1 ucredit=-1 dcredit=-1 [badwords=first2012++]
password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass remember=5 use_authtok
password    required      pam_deny.so

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
-session     optional      pam_systemd.so
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_unix.so

EOF

